using System.Collections.Generic;
using System;

namespace Commons.Utils
{
	[Serializable]
	public class HashMultiMap<K, V>
	{
		private Dictionary<K, List<V>> dictionary;
		private int listCapacity;
		
		public HashMultiMap ()
		{
			dictionary = new Dictionary<K, List<V>>();	
		}
		
		public HashMultiMap (int capacity)
		{
			dictionary = new Dictionary<K, List<V>>(capacity);
		}
		
		public HashMultiMap (int capacity, int listCapacity)
		{
			dictionary = new Dictionary<K, List<V>>(capacity);
			this.listCapacity = listCapacity;
		}

		public int TotalCount { get; private set; }

		public int Count
		{
			get
			{
				return dictionary.Count;
			}
		}

		public IEnumerable<K> Keys
		{
			get
			{
				return dictionary.Keys;
			}
		}

		public IEnumerable<V> Values
		{
			get
			{
				foreach (List<V> list in dictionary.Values)
				{
					foreach (V val in list)
					{
						yield return val;
					}
				}
			}
		}

		public void Add(K key, V value)
		{
			List<V> list;
			if (!dictionary.TryGetValue(key, out list))
			{
				if (listCapacity > 0)
				{
					list = dictionary[key] = new List<V>(listCapacity);
				}
				else
				{
					list = dictionary[key] = new List<V>();
				}
			}
			list.Add(value);
			TotalCount++;
		}

		public bool Remove(K key)
		{
			return dictionary.Remove(key);
		}

		public bool Remove(K key, V value)
		{
			List<V> list;
			if (dictionary.TryGetValue(key, out list))
			{
				if (list.Remove(value))
				{
					TotalCount--;

					if (list.Count == 0)
					{
						dictionary.Remove(key);
					}

					return true;
				}
			}

			return false;
		}

		public void Clear()
		{
			dictionary.Clear();
		}

		public bool ContainsKey(K key)
		{
			return dictionary.ContainsKey(key);
		}

		public List<V> Get(K key)
		{
			List<V> list;

			return dictionary.TryGetValue(key, out list) ? list : null;
		}

		public List<V> this[K key]
		{
			get
			{	
				return Get(key);
			}
		}
	}
}

